home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / pyshared / xdg / IniFile.py < prev    next >
Encoding:
Python Source  |  2010-06-23  |  12.2 KB  |  410 lines

  1. """
  2. Base Class for DesktopEntry, IconTheme and IconData
  3. """
  4.  
  5. import re, os, stat, codecs
  6. from Exceptions import *
  7. import xdg.Locale
  8.  
  9. class IniFile:
  10.     defaultGroup = ''
  11.     fileExtension = ''
  12.  
  13.     filename = ''
  14.  
  15.     tainted = False
  16.  
  17.     def __init__(self, filename=None):
  18.         self.content = dict()
  19.         if filename:
  20.             self.parse(filename)
  21.  
  22.     def __cmp__(self, other):
  23.         return cmp(self.content, other.content)
  24.  
  25.     def parse(self, filename, headers=None):
  26.         '''
  27.         headers -- list of headers the parser will try to select as a default header
  28.         '''
  29.         # for performance reasons
  30.         content = self.content
  31.  
  32.         if not os.path.isfile(filename):
  33.             raise ParsingError("File not found", filename)
  34.  
  35.         try:
  36.             fd = file(filename, 'r')
  37.         except IOError, e:
  38.             if debug:
  39.                 raise e
  40.             else:
  41.                 return
  42.  
  43.         # parse file
  44.         for line in fd:
  45.             line = line.strip()
  46.             # empty line
  47.             if not line:
  48.                 continue
  49.             # comment
  50.             elif line[0] == '#':
  51.                 continue
  52.             # new group
  53.             elif line[0] == '[':
  54.                 currentGroup = line.lstrip("[").rstrip("]")
  55.                 if debug and self.hasGroup(currentGroup):
  56.                     raise DuplicateGroupError(currentGroup, filename)
  57.                 else:
  58.                     content[currentGroup] = {}
  59.             # key
  60.             else:
  61.                 index = line.find("=")
  62.                 key = line[0:index].strip()
  63.                 value = line[index+1:].strip()
  64.                 try:
  65.                     if debug and self.hasKey(key, currentGroup):
  66.                         raise DuplicateKeyError(key, currentGroup, filename)
  67.                     else:
  68.                         content[currentGroup][key] = value
  69.                 except (IndexError, UnboundLocalError):
  70.                     raise ParsingError("Parsing error on key, group missing", filename)
  71.  
  72.         fd.close()
  73.  
  74.         self.filename = filename
  75.         self.tainted = False
  76.  
  77.         # check header
  78.         if headers:
  79.             for header in headers:
  80.                 if content.has_key(header):
  81.                     self.defaultGroup = header
  82.                     break
  83.             else:
  84.                 raise ParsingError("[%s]-Header missing" % headers[0], filename)
  85.  
  86.     # start stuff to access the keys
  87.     def get(self, key, group=None, locale=False, type="string", list=False):
  88.         # set default group
  89.         if not group:
  90.             group = self.defaultGroup
  91.  
  92.         # return key (with locale)
  93.         if self.content.has_key(group) and self.content[group].has_key(key):
  94.             if locale:
  95.                 value = self.content[group][self.__addLocale(key, group)]
  96.             else:
  97.                 value = self.content[group][key]
  98.         else:
  99.             if debug:
  100.                 if not self.content.has_key(group):
  101.                     raise NoGroupError(group, self.filename)
  102.                 elif not self.content[group].has_key(key):
  103.                     raise NoKeyError(key, group, self.filename)
  104.             else:
  105.                 value = ""
  106.  
  107.         if list == True:
  108.             values = self.getList(value)
  109.             result = []
  110.         else:
  111.             values = [value]
  112.  
  113.         for value in values:
  114.             if type == "string" and locale == True:
  115.                 value = value.decode("utf-8", "ignore")
  116.             elif type == "boolean":
  117.                 value = self.__getBoolean(value)
  118.             elif type == "integer":
  119.                 try:
  120.                     value = int(value)
  121.                 except ValueError:
  122.                     value = 0
  123.             elif type == "numeric":
  124.                 try:
  125.                     value = float(value)
  126.                 except ValueError:
  127.                     value = 0.0
  128.             elif type == "regex":
  129.                 value = re.compile(value)
  130.             elif type == "point":
  131.                 value = value.split(",")
  132.  
  133.             if list == True:
  134.                 result.append(value)
  135.             else:
  136.                 result = value
  137.  
  138.         return result
  139.     # end stuff to access the keys
  140.  
  141.     # start subget
  142.     def getList(self, string):
  143.         if re.search(r"(?<!\\)\;", string):
  144.             list = re.split(r"(?<!\\);", string)
  145.         elif re.search(r"(?<!\\)\|", string):
  146.             list = re.split(r"(?<!\\)\|", string)
  147.         elif re.search(r"(?<!\\),", string):
  148.             list = re.split(r"(?<!\\),", string)
  149.         else:
  150.             list = [string]
  151.         if list[-1] == "":
  152.             list.pop()
  153.         return list
  154.  
  155.     def __getBoolean(self, boolean):
  156.         if boolean == 1 or boolean == "true" or boolean == "True":
  157.             return True
  158.         elif boolean == 0 or boolean == "false" or boolean == "False":
  159.             return False
  160.         return False
  161.     # end subget
  162.  
  163.     def __addLocale(self, key, group=None):
  164.         "add locale to key according the current lc_messages"
  165.         # set default group
  166.         if not group:
  167.             group = self.defaultGroup
  168.  
  169.         for lang in xdg.Locale.langs:
  170.             if self.content[group].has_key(key+'['+lang+']'):
  171.                 return key+'['+lang+']'
  172.  
  173.         return key
  174.  
  175.     # start validation stuff
  176.     def validate(self, report="All"):
  177.         "validate ... report = All / Warnings / Errors"
  178.  
  179.         self.warnings = []
  180.         self.errors = []
  181.  
  182.         # get file extension
  183.         self.fileExtension = os.path.splitext(self.filename)[1]
  184.  
  185.         # overwrite this for own checkings
  186.         self.checkExtras()
  187.  
  188.         # check all keys
  189.         for group in self.content:
  190.             self.checkGroup(group)
  191.             for key in self.content[group]:
  192.                 self.checkKey(key, self.content[group][key], group)
  193.                 # check if value is empty
  194.                 if self.content[group][key] == "":
  195.                     self.warnings.append("Value of Key '%s' is empty" % key)
  196.  
  197.         # raise Warnings / Errors
  198.         msg = ""
  199.  
  200.         if report == "All" or report == "Warnings":
  201.             for line in self.warnings:
  202.                 msg += "\n- " + line
  203.  
  204.         if report == "All" or report == "Errors":
  205.             for line in self.errors:
  206.                 msg += "\n- " + line
  207.  
  208.         if msg:
  209.             raise ValidationError(msg, self.filename)
  210.  
  211.     # check if group header is valid
  212.     def checkGroup(self, group):
  213.         pass
  214.  
  215.     # check if key is valid
  216.     def checkKey(self, key, value, group):
  217.         pass
  218.  
  219.     # check random stuff
  220.     def checkValue(self, key, value, type="string", list=False):
  221.         if list == True:
  222.             values = self.getList(value)
  223.         else:
  224.             values = [value]
  225.  
  226.         for value in values:
  227.             if type == "string":
  228.                 code = self.checkString(value)
  229.             elif type == "boolean":
  230.                 code = self.checkBoolean(value)
  231.             elif type == "numeric":
  232.                 code = self.checkNumber(value)
  233.             elif type == "integer":
  234.                 code = self.checkInteger(value)
  235.             elif type == "regex":
  236.                 code = self.checkRegex(value)
  237.             elif type == "point":
  238.                 code = self.checkPoint(value)
  239.             if code == 1:
  240.                 self.errors.append("'%s' is not a valid %s" % (value, type))
  241.             elif code == 2:
  242.                 self.warnings.append("Value of key '%s' is deprecated" % key)
  243.  
  244.     def checkExtras(self):
  245.         pass
  246.  
  247.     def checkBoolean(self, value):
  248.         # 1 or 0 : deprecated
  249.         if (value == "1" or value == "0"):
  250.             return 2
  251.         # true or false: ok
  252.         elif not (value == "true" or value == "false"):
  253.             return 1
  254.  
  255.     def checkNumber(self, value):
  256.         # float() ValueError
  257.         try:
  258.             float(value)
  259.         except:
  260.             return 1
  261.  
  262.     def checkInteger(self, value):
  263.         # int() ValueError
  264.         try:
  265.             int(value)
  266.         except:
  267.             return 1
  268.  
  269.     def checkPoint(self, value):
  270.         if not re.match("^[0-9]+,[0-9]+$", value):
  271.             return 1
  272.  
  273.     def checkString(self, value):
  274.         # convert to ascii
  275.         if not value.decode("utf-8", "ignore").encode("ascii", 'ignore') == value:
  276.             return 1
  277.  
  278.     def checkRegex(self, value):
  279.         try:
  280.             re.compile(value)
  281.         except:
  282.             return 1
  283.  
  284.     # write support
  285.     def write(self, filename=None, trusted=False):
  286.         if not filename and not self.filename:
  287.             raise ParsingError("File not found", "")
  288.  
  289.         if filename:
  290.             self.filename = filename
  291.         else:
  292.             filename = self.filename
  293.  
  294.         if os.path.dirname(filename) and not os.path.isdir(os.path.dirname(filename)):
  295.             os.makedirs(os.path.dirname(filename))
  296.  
  297.         fp = codecs.open(filename, 'w')
  298.  
  299.         # An executable bit signifies that the desktop file is
  300.         # trusted, but then the file can be executed. Add hashbang to
  301.         # make sure that the file is opened by something that
  302.         # understands desktop files.
  303.         if trusted:
  304.             fp.write("#!/usr/bin/env xdg-open\n")
  305.  
  306.         if self.defaultGroup:
  307.             fp.write("[%s]\n" % self.defaultGroup)
  308.             for (key, value) in self.content[self.defaultGroup].items():
  309.                 fp.write("%s=%s\n" % (key, value))
  310.             fp.write("\n")
  311.         for (name, group) in self.content.items():
  312.             if name != self.defaultGroup:
  313.                 fp.write("[%s]\n" % name)
  314.                 for (key, value) in group.items():
  315.                     fp.write("%s=%s\n" % (key, value))
  316.                 fp.write("\n")
  317.  
  318.         # Add executable bits to the file to show that it's trusted.
  319.         if trusted:
  320.             oldmode = os.stat(filename).st_mode
  321.             mode = oldmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
  322.             os.chmod(filename, mode)
  323.  
  324.         self.tainted = False
  325.  
  326.     def set(self, key, value, group=None, locale=False):
  327.         # set default group
  328.         if not group:
  329.             group = self.defaultGroup
  330.  
  331.         if locale == True and len(xdg.Locale.langs) > 0:
  332.             key = key + "[" + xdg.Locale.langs[0] + "]"
  333.  
  334.         try:
  335.             if isinstance(value, unicode):
  336.                 self.content[group][key] = value.encode("utf-8", "ignore")
  337.             else:
  338.                 self.content[group][key] = value
  339.         except KeyError:
  340.             raise NoGroupError(group, self.filename)
  341.             
  342.         self.tainted = (value == self.get(key, group))
  343.  
  344.     def addGroup(self, group):
  345.         if self.hasGroup(group):
  346.             if debug:
  347.                 raise DuplicateGroupError(group, self.filename)
  348.             else:
  349.                 pass
  350.         else:
  351.             self.content[group] = {}
  352.             self.tainted = True
  353.  
  354.     def removeGroup(self, group):
  355.         existed = group in self.content
  356.         if existed:
  357.             del self.content[group]
  358.             self.tainted = True
  359.         else:
  360.             if debug:
  361.                 raise NoGroupError(group, self.filename)
  362.         return existed
  363.  
  364.     def removeKey(self, key, group=None, locales=True):
  365.         # set default group
  366.         if not group:
  367.             group = self.defaultGroup
  368.  
  369.         try:
  370.             if locales:
  371.                 for (name, value) in self.content[group].items():
  372.                     if re.match("^" + key + xdg.Locale.regex + "$", name) and name != key:
  373.                         value = self.content[group][name]
  374.                         del self.content[group][name]
  375.             value = self.content[group][key]
  376.             del self.content[group][key]
  377.             self.tainted = True
  378.             return value
  379.         except KeyError, e:
  380.             if debug:
  381.                 if e == group:
  382.                     raise NoGroupError(group, self.filename)
  383.                 else:
  384.                     raise NoKeyError(key, group, self.filename)
  385.             else:
  386.                 return ""
  387.  
  388.     # misc
  389.     def groups(self):
  390.         return self.content.keys()
  391.  
  392.     def hasGroup(self, group):
  393.         if self.content.has_key(group):
  394.             return True
  395.         else:
  396.             return False
  397.  
  398.     def hasKey(self, key, group=None):
  399.         # set default group
  400.         if not group:
  401.             group = self.defaultGroup
  402.  
  403.         if self.content[group].has_key(key):
  404.             return True
  405.         else:
  406.             return False
  407.  
  408.     def getFileName(self):
  409.         return self.filename
  410.